/* *************************************** */
/* * PPM Functions Library               * */
/* * Authors:                            * */
/* *  André Bannwart Perina      7152757 * */
/* *  Rodrigo de Freitas Pereira 7573472 * */
/* *  Thaís Emanuele dos Santos  6453087 * */
/* *************************************** */

#ifndef PPM_FUNCS_H
#define PPM_FUNCS_H

/* Channel Constants */
#define PPM_CHANNEL_R 0
#define PPM_CHANNEL_G 1
#define PPM_CHANNEL_B 2

/* Format Constants */
#define PPM_FORMAT_P3 3
#define PPM_FORMAT_P6 6

/* Error Constants */
#define PPM_SUCCESS 0
#define PPM_ERR_MALLOC_ERROR -1
#define PPM_ERR_INVALID_FILE -2
#define PPM_ERR_INVALID_FORMAT -3
#define PPM_ERR_INVALID_MAXVAL -4
#define PPM_ERR_INVALID_FORMAT_PARAMETER -5
#define PPM_ERR_CHANNEL_SIZES_MISMATCH -6
#define PPM_ERR_INVALID_CHANNEL_PARAMETER -7
#define PPM_ERR_INVALID_BORDER_PARAMETER -8
#define PPM_ERR_INVALID_WIDTH_PARAMETER -9
#define PPM_ERR_INVALID_SEGMENT_PARAMETERS -10
#define PPM_ERR_SEG_EXISTS -11
#define PPM_ERR_INVALID_ORIENTATION_PARAMETER -12

/* Border Constants */
#define PPM_BORDER_TOP 0
#define PPM_BORDER_BOTTOM 1
#define PPM_BORDER_LEFT 2
#define PPM_BORDER_RIGHT 3

/* Concatenation Constants */
#define PPM_CONCAT_TOP 0
#define PPM_CONCAT_BOTTOM 1
#define PPM_CONCAT_LEFT 2
#define PPM_CONCAT_RIGHT 3

/* ** Create a PPM Referenced Segment *************************************************************** */
/* * Description: Creates a PPM Referenced Segment. This segment references another segment (or     * */
/* *              part of it) and should not be manipulated. There is no write-protection to this,  * */
/* *              so developer should use it carefully                                              * */
/* * Inputs: - Segment pointer to receive created segment                                           * */
/* * Outputs: - PPM_ERR_MALLOC_ERROR if malloc fails, or PPM_SUCCESS if no errors are found         * */
/* * Compatibility: PPM Referenced Segment                                                          * */
/* ************************************************************************************************** */
#define ppm_create_ref(a) ppm_create(a)

/* ** Create a PPM Constant Segment ***************************************************************** */
/* * Description: Creates a PPM Constant Segment. This segment is allocated in one big segment of   * */
/* *              memory for easy access. It should not be resized. There is no protection to this, * */
/* *              so developer should use it carefully                                              * */
/* * Inputs: - Segment pointer to receive created segment                                           * */
/* * Outputs: - PPM_ERR_MALLOC_ERROR if malloc fails, or PPM_SUCCESS if no errors are found         * */
/* * Compatibility: PPM Constant Segment                                                            * */
/* ************************************************************************************************** */
#define ppm_create_const(a) ppm_create(a)

/* Byte type */
typedef char byte;

/* Segment Structure */
typedef struct {
	/* Segment data */
	byte **d;
	/* Number of lines */
	int m;
	/* Number of columns */
	int n;
} ppm_seg_t;

/* ** Create a PPM Standard Segment ***************************************************************** */
/* * Description: Creates a PPM Standard Segment. This segment is allocated a double pointer        * */
/* *              scheme, being easily resizable                                                    * */
/* * Inputs: - seg: Segment pointer to receive created segment                                      * */
/* * Outputs: PPM_ERR_MALLOC_ERROR if malloc fails, or PPM_SUCCESS if no errors were found          * */
/* * Compatibility: PPM Standard Segment                                                            * */
/* ************************************************************************************************** */
int ppm_create(ppm_seg_t **);

/* ** Destroy a PPM Standard Segment **************************************************************** */
/* * Description: Destroys a PPM Standard Segment                                                   * */
/* * Inputs: - seg: Segment to be destroyed                                                         * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Standard Segment                                                            * */
/* ************************************************************************************************** */
int ppm_destroy(ppm_seg_t **);

/* ** Destroy a PPM Referenced Segment ************************************************************** */
/* * Description: Destroys a PPM Referenced Segment                                                 * */
/* * Inputs: - seg: Segment to be destroyed                                                         * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Referenced Segment                                                          * */
/* ************************************************************************************************** */
int ppm_destroy_ref(ppm_seg_t **);

/* ** Destroy a PPM Constant Segment **************************************************************** */
/* * Description: Destroys a PPM Constant Segment                                                   * */
/* * Inputs: - seg: Segment to be destroyed                                                         * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Constant Segment                                                            * */
/* ************************************************************************************************** */
int ppm_destroy_const(ppm_seg_t **);

/* ** Clear a PPM Standard Segment ****************************************************************** */
/* * Description: Clears a PPM Standard Segment. It is equivalent to destroying and creating a      * */
/* *              segment                                                                           * */
/* * Inputs: - seg: Segment to be erased                                                            * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Standard Segment                                                            * */
/* ************************************************************************************************** */
int ppm_clear(ppm_seg_t *);

/* ** Clear a PPM Referenced Segment **************************************************************** */
/* * Description: Clears (de-references) a PPM Referenced Segment. It is equivalent to destroying   * */
/* *              and creating a segment                                                            * */
/* * Inputs: - seg: Segment to be erased                                                            * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Referenced Segment                                                          * */
/* ************************************************************************************************** */
int ppm_clear_ref(ppm_seg_t *);

/* ** Clear a PPM Constant Segment ****************************************************************** */
/* * Description: Clears a PPM Constant Segment. It is equivalent to destroying and creating a      * */
/* *              segment                                                                           * */
/* * Inputs: - seg: Segment to be erased                                                            * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Constant Segment                                                            * */
/* ************************************************************************************************** */
int ppm_clear_const(ppm_seg_t *);

/* ** Set a PPM Standard Segment ******************************************************************** */
/* * Description: Set a PPM Standard Segment according to an input matrix. The data is copied.      * */
/* * Inputs: - d: Input Matrix Data                                                                 * */
/* *         - seg: Segment to be fulfilled                                                         * */
/* *         - m: Number of lines present in d                                                      * */
/* *         - n: Number of columns present in d                                                    * */
/* * Outputs: PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard Segment                                                            * */
/* ************************************************************************************************** */
int ppm_set(byte **, ppm_seg_t *, unsigned int, unsigned int);

/* ** Copy a PPM Standard Segment ******************************************************************* */
/* * Description: Copy a PPM Standard Segment according to another PPM Segment                      * */
/* * Inputs: - input: Input Segment                                                                 * */
/* *         - output: Output Segment                                                               * */
/* * Outputs: PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard, Referenced or Constant (input), PPM Standard Segment (output)     * */            
/* ************************************************************************************************** */
int ppm_copy(ppm_seg_t *, ppm_seg_t *);

/* ** Get PPM Size from a File ********************************************************************** */
/* * Description: Ditto                                                                             * */
/* * Inputs: - fileName: File Name                                                                  * */
/* *         - format: PPM Format (PPM_FORMAT_P3 or PPM_FORMAT_P6)                                  * */
/* *         - m: Reference to integer where number of lines will be stored                         * */
/* *         - n: Reference to integer where number of columns will be stored                       * */
/* * Outputs: PPM_ERR_INVALID_FILE if no file was opened, PPM_ERR_INVALID_FORMAT if format was not  * */
/* *          as specified or PPM_SUCCESS if no errors were found                                   * */
/* ************************************************************************************************** */
int ppm_get_size(char *, unsigned int, unsigned int *, unsigned int *);

/* ** Set a PPM Standard Segment from a File ******************************************************** */
/* * Description: Reads a channel from a file and stores in a PPM Standard Segment                  * */
/* * Inputs: - fileName: File Name                                                                  * */
/* *         - channel: Colour Channel (PPM_FORMAT_R, PPM_FORMAT_G or PPM_FORMAT_B)                 * */
/* *         - format: PPM Format (PPM_FORMAT_P3 or PPM_FORMAT_P6)                                  * */
/* *         - seg: Segment to be fulfilled                                                         * */
/* * Outputs: PPM_ERR_INVALID_FILE if no file was opened, PPM_ERR_INVALID_FORMAT if format was not  * */
/* *          as specified, PPM_ERR_SEG_EXISTS if segment has already data,                         * */
/* *          PPM_ERR_INVALID_CHANNEL_PARAMETER if specified channel is invalid,                    * */
/* *          PPM_ERR_INVALID_MAXVAL if maximum value is different from 255,                        * */
/* *          PPM_ERR_INVALID_FORMAT_PARAMETER if format parameter differs from file format or      * */
/* *          PPM_SUCCESS if no errors were found                                                   * */
/* * Compatibility: PPM Standard Segment                                                            * */            
/* ************************************************************************************************** */
int ppm_get_channel(char *, unsigned int, unsigned int, ppm_seg_t *);

/* ** Set a PPM Constant Segment from a File ******************************************************** */
/* * Description: Reads a channel from a file and stores in a PPM Constant Segment                  * */
/* * Inputs: - fileName: File Name                                                                  * */
/* *         - channel: Colour Channel (PPM_FORMAT_R, PPM_FORMAT_G or PPM_FORMAT_B)                 * */
/* *         - format: PPM Format (PPM_FORMAT_P3 or PPM_FORMAT_P6)                                  * */
/* *         - seg: Segment to be fulfilled                                                         * */
/* * Outputs: PPM_ERR_INVALID_FILE if no file was opened, PPM_ERR_INVALID_FORMAT if format was not  * */
/* *          as specified, PPM_ERR_SEG_EXISTS if segment has already data,                         * */
/* *          PPM_ERR_INVALID_CHANNEL_PARAMETER if specified channel is invalid,                    * */
/* *          PPM_ERR_INVALID_MAXVAL if maximum value is different from 255,                        * */
/* *          PPM_ERR_INVALID_FORMAT_PARAMETER if format parameter differs from file format or      * */
/* *          PPM_SUCCESS if no errors were found                                                   * */
/* * Compatibility: PPM Constant Segment                                                            * */            
/* ************************************************************************************************** */
int ppm_get_channel_const(char *, unsigned int, unsigned int, ppm_seg_t *);

/* ** Set a File from three PPM Segments ************************************************************ */
/* * Description: Saves a file using three PPM Segments, one for each colour channel                * */
/* * Inputs: - fileName: File Name                                                                  * */
/* *         - format: PPM Format (PPM_FORMAT_P3 or PPM_FORMAT_P6)                                  * */
/* *         - r: Red Channel Segment                                                               * */
/* *         - g: Green Channel Segment                                                             * */
/* *         - b: Blue Channel Segment                                                              * */
/* * Outputs: PPM_ERR_INVALID_FILE if no file was opened, PPM_ERR_CHANNEL_SIZES_MISMATCH if colour  * */
/* *          segments have different sizes, PPM_ERR_INVALID_FORMAT_PARAMETER if format parameter   * */
/* *          is invalid or PPM_SUCCESS if no errors were found                                     * */
/* * Compatibility: PPM Standard, Referenced or Constant Segment                                    * */            
/* ************************************************************************************************** */
int ppm_set_file(char *, unsigned int, ppm_seg_t *, ppm_seg_t *, ppm_seg_t *);

/* ** Dump Channel Segments to a File *************************************************************** */
/* * Description: Dump colour channels to a file without specifying PPM header, useful for          * */
/* *              concatenation                                                                     * */
/* * Inputs: - fileName: File Name                                                                  * */
/* *         - format: PPM Format (PPM_FORMAT_P3 or PPM_FORMAT_P6)                                  * */
/* *         - r: Red Channel Segment                                                               * */
/* *         - g: Green Channel Segment                                                             * */
/* *         - b: Blue Channel Segment                                                              * */
/* * Outputs: PPM_ERR_INVALID_FILE if no file was opened, PPM_ERR_CHANNEL_SIZES_MISMATCH if colour  * */
/* *          segments have different sizes, PPM_ERR_INVALID_FORMAT_PARAMETER if format parameter   * */
/* *          is invalid or PPM_SUCCESS if no errors were found                                     * */
/* * Compatibility: PPM Standard, Referenced or Constant Segment                                    * */            
/* ************************************************************************************************** */
int ppm_file_dump(char *, unsigned int, ppm_seg_t *, ppm_seg_t *, ppm_seg_t *);

/* ** Pack a Segment ******************************************************************************** */
/* * Description: Packs a Segment to a 1-dimensional contiguous array without size information      * */
/* * Inputs: - input: Segment to be packed                                                          * */
/* *         - output: Pointer to byte array that will received the packed segment                  * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Standard, Referenced or Constant Segment                                    * */            
/* ************************************************************************************************** */
int ppm_pack(ppm_seg_t *, byte **);

/* ** Pack Multiple Segments ************************************************************************ */
/* * Description: Packs various Segments to a 1-dimensional contiguous array without size           * */
/* *              information. There is no physical indication of boundaries between segments       * */
/* * Inputs: - num: Number of Segments to be packed                                                 * */
/* *         - seg0, seg1, ... segn: All segments that will be packed. Should be equal to num       * */
/* *           segments                                                                             * */
/* *         - output: Pointer to byte array that will received all packed segments                 * */
/* * Outputs: PPM_SUCCESS                                                                           * */
/* * Compatibility: PPM Standard, Referenced or Constant Segment                                    * */ 
/* * Usage: ppm_pack_n(4, seg0, seg1, seg2, seg3, &output);                                         * */           
/* ************************************************************************************************** */
int ppm_pack_n(unsigned int, ...);

/* ** Unpack a Segment ****************************************************************************** */
/* * Description: Unpacks a 1-dimensional contiguous array into a Segment.                          * */
/* * Inputs: - input: Byte Array that contains the segment                                          * */
/* *         - output: Segment to be fulfilled                                                      * */
/* *         - m: Number of lines                                                                   * */
/* *         - n: Number of columns                                                                 * */
/* * Outputs: PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard                                                                    * */            
/* ************************************************************************************************** */
int ppm_unpack(byte *, ppm_seg_t *, unsigned int, unsigned int);

/* ** Unpack Multiple Segments ********************************************************************** */
/* * Description: Unpacks a 1-dimensional contiguous array into various Segments.                   * */
/* * Inputs: - num: Number of Segments to be unpacked                                               * */
/* *         - input: Byte Array that contain all segments                                          * */
/* *         - output0: First Segment to be fulfilled                                               * */
/* *         - n0: Number of lines for first segment                                                * */
/* *         - m0: Number of columns for first segment                                              * */
/* *         - ...                                                                                  * */
/* *         - outputn: Last Segment to be fulfilled                                                * */
/* *         - nn: Number of lines for last segment                                                 * */
/* *         - mn: Number of columns for last segment                                               * */
/* * Outputs: PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard                                                                    * */
/* * Usage: ppm_unpack_n(4, input, seg0, m0, n0, seg1, m1, n1, seg2, m2, n2, seg3, m3, n3);         * */             
/* ************************************************************************************************** */
int ppm_unpack_n(unsigned int, ...);

/* ** Get a Sub-Segment from a Segment ************************************************************** */
/* * Description: Gets a piece from a Segment                                                       * */
/* * Inputs: - input: Input Segment                                                                 * */
/* *         - output: Segment to receive the Sub-Segment from Input                                * */
/* *         - l: Line to start the Sub-Segment (inclusive)                                         * */
/* *         - c: Column to start the Sub-Segment (inclusive)                                       * */
/* *         - m: Number of lines from l                                                            * */
/* *         - n: Number of columns from c                                                          * */
/* * Outputs: PPM_ERR_INVALID_SEGMENT_PARAMETERS if any offset is bigger than the own segment,      * */
/* *          PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard, Reference or Constant (input), PPM Standard (output)              * */            
/* ************************************************************************************************** */
int ppm_get_segment(ppm_seg_t *, ppm_seg_t *, unsigned int, unsigned int, unsigned int, unsigned int);

/* ** Reference a Sub-Segment from a Segment ******************************************************** */
/* * Description: Gets a piece from a Segment and stores as reference on another Segment            * */
/* * Inputs: - input: Input Segment                                                                 * */
/* *         - output: Segment to receive the references from Sub-Segment from Input                * */
/* *         - l: Line to start the Sub-Segment (inclusive)                                         * */
/* *         - c: Column to start the Sub-Segment (inclusive)                                       * */
/* *         - m: Number of lines from l                                                            * */
/* *         - n: Number of columns from c                                                          * */
/* * Outputs: PPM_ERR_INVALID_SEGMENT_PARAMETERS if any offset is bigger than the own segment,      * */
/* *          PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard, Reference or Constant (input), PPM Reference (output). Please     * */  
/* *                note that recursive referencing may happen                                      * */          
/* ************************************************************************************************** */
int ppm_get_segment_ref(ppm_seg_t *, ppm_seg_t *, unsigned int, unsigned int, unsigned int, unsigned int);

/* ** Concatenate one Segment to Another ************************************************************ */
/* * Description: Concatenates one segment into another by copying. Segments must match number of   * */
/* *              lines for left and right orientations or number of columns for top or bottom      * */
/* * Inputs: - input: Segment to be concatenated                                                    * */
/* *         - output: Segment to receive the concatenation. If output is empty, this function will * */
/* *                   act as ppm_copy                                                              * */
/* *         - orientation: Concatenation Orientation (PPM_CONCAT_TOP, PPM_CONCAT_BOTTOM,           * */
/* *                        PPM_CONCAT_LEFT or PPM_CONCAT_RIGHT)                                    * */
/* * Outputs: PPM_ERR_INVALID_ORIENTATION_PARAMETER if orientation is invalid or PPM_SUCCESS if no  * */
/* *          errors were found                                                                     * */
/* * Compatibility: PPM Standard, Reference or Constant (input), PPM Standard (output)              * */       
/* ************************************************************************************************** */
int ppm_concat_segment(ppm_seg_t *, ppm_seg_t *, unsigned int);

/* ** Add Black Border to Segment ******************************************************************* */
/* * Description: Adds a black border to a segment                                                  * */
/* * Inputs: - seg: Segment to receive the border                                                   * */
/* *         - border: Border Orientation (PPM_BORDER_TOP, PPM_BORDER_BOTTOM, PPM_BORDER_LEFT or    * */
/* *                   PPM_BORDER_RIGHT                                                             * */
/* *         - width: Border Size                                                                   * */
/* * Outputs: PPM_ERR_INVALID_WIDTH_PARAMETER if width is negative or zero,                         * */
/* *          PPM_ERR_INVALID_BORDER_PARAMETER if orientation is invalid or PPM_SUCCESS if no       * */
/* *          errors were found                                                                     * */
/* * Compatibility: PPM Standard                                                                    * */       
/* ************************************************************************************************** */
int ppm_add_border(ppm_seg_t *, unsigned int, unsigned int);

/* ** Remove Border from Segment ******************************************************************** */
/* * Description: Removes a border from a segment                                                   * */
/* * Inputs: - seg: Segment to have the border removed                                              * */
/* *         - border: Border Orientation (PPM_BORDER_TOP, PPM_BORDER_BOTTOM, PPM_BORDER_LEFT or    * */
/* *                   PPM_BORDER_RIGHT                                                             * */
/* *         - width: Border Size                                                                   * */
/* * Outputs: PPM_ERR_INVALID_WIDTH_PARAMETER if width is negative or zero,                         * */
/* *          PPM_ERR_INVALID_BORDER_PARAMETER if orientation is invalid or PPM_SUCCESS if no       * */
/* *          errors were found                                                                     * */
/* * Compatibility: PPM Standard                                                                    * */       
/* ************************************************************************************************** */
int ppm_remove_border(ppm_seg_t *, unsigned int, unsigned int);

/* ** Smooth Segment ******************************************************************************** */
/* * Description: Applies Smooth to a Segment using a 5x5 stencil. The first and last two columns   * */
/* *              and lines the smoothing is not applied                                            * */
/* * Inputs: - input: Segment to have the effect appllied                                           * */
/* *         - output: Output Segment                                                               * */
/* * Outputs: PPM_ERR_SEG_EXISTS if segment has already data or PPM_SUCCESS if no errors were found * */
/* * Compatibility: PPM Standard, Reference or Constant (input), PPM Standard (output)              * */       
/* ************************************************************************************************** */
int ppm_smooth(ppm_seg_t *, ppm_seg_t *);

#endif